package cn.iocoder.yudao.framework.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.exception.KnownServiceException;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpStatus;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * 类似 PHP 的 http_build_query 函数，支持多维数组和嵌套结构。
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/03/11
 */
@SuppressWarnings("unused")
@UtilityClass
@Slf4j
public class HttpUtils {

    public static String executeFormPost(@Nonnull String url, @Nonnull List<NameValuePair> kvPairs) {
        Assertions.notBlank(url, "请求地址不能为空");
        CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(RequestConfig.custom()
                        .setSocketTimeout(30000)//读取超时
                        .setConnectTimeout(30000)//连接超时
                        .build())
                .build();
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nameValuePairs = new ArrayList<>();
        if (CollUtil.isNotEmpty(kvPairs)) {
            nameValuePairs.addAll(kvPairs);
        }
        CloseableHttpResponse response = null;
        String result = null;
        try {
            log.info("Sending post request to {} with params: {}", url, nameValuePairs);
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, StandardCharsets.UTF_8));
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.OK.value()) {
                HttpEntity httpentity = response.getEntity();
                if (httpentity != null) {
                    result = EntityUtils.toString(httpentity);
                }
            }
            log.info("Received response with status code {}:\n{}", statusCode, result);
        } catch (Exception e) {
            log.warn("Error occurred while sending post request to {}", url, e);
        } finally {
            IoUtil.close(response);
            IoUtil.close(httpClient);
        }
        return result;
    }

    @Nullable
    public static List<Integer> queryStringToIntegers(String queryString) {
        return queryStringToList(queryString, Integer::parseInt);
    }

    @Nullable
    public static List<Long> queryStringToLongs(String queryString) {
        return queryStringToList(queryString, Long::parseLong);
    }

    @Nullable
    public static List<String> queryStringToStrings(String queryString) {
        return queryStringToList(queryString, String::valueOf);
    }

    @Nullable
    public static <T> List<T> queryStringToList(String queryString, Function<String, T> function) {
        if (StrUtil.isBlank(queryString)) {
            return null;
        }
        try {
            if (queryString.contains("[")) {
                // 兼容 JSON 数组的传参
                return JsonUtils.parseArray(queryString, String.class).stream().map(function).toList();
            }
            if (queryString.contains(",")) {
                // 兼容英文逗号分隔的传参
                return Arrays.stream(queryString.split(",")).map(function).toList();
            }
        } catch (Exception e) {
            throw new KnownServiceException("参数解析异常：" + queryString);
        }
        return Stream.of(queryString).map(function).toList();
    }

    public static String buildQueryString(Map<String, ?> data) {
        return buildQueryString(data, false);
    }

    public static String buildQueryString(Map<String, ?> data, boolean urlEncoded) {
        List<NameValuePair> params = new ArrayList<>();
        for (Map.Entry<String, ?> entry : data.entrySet()) {
            addParams(entry.getKey(), entry.getValue(), params, urlEncoded);
        }
        if (urlEncoded) {
            return URLEncodedUtils.format(params, StandardCharsets.UTF_8);
        }
        // 生成查询字符串
        String[] strings = params.stream()
                // 修复含数组格式 Comparator.comparing(NameValuePair::getName) 的错误排序
                .sorted((a, b) -> {
                    try {
                        // PHP兼容数组参数的比较，如：idArr[0]、idArr[1]、idArr[10]
                        if (a.getName().contains("[") && a.getName().contains("]")) {
                            int numA = Integer.parseInt(extractArrayIndex(a.getName()));
                            int numB = Integer.parseInt(extractArrayIndex(b.getName()));
                            return Integer.compare(numA, numB);
                        }
                    } catch (NumberFormatException e) {
                        return a.getName().compareTo(b.getName());
                    }
                    return a.getName().compareTo(b.getName());
                })
                .map(entry -> entry.getName() + "=" + entry.getValue())
                .toArray(String[]::new);
        String queryString = StrUtil.join("&", (Object) strings);
        // 去除字符串中的空格
        queryString = queryString.replaceAll("\\s+", "");
        return queryString;
    }

    private static void addParams(String prefix, Object value, List<NameValuePair> params, boolean urlEncoded) {
        if (value == null) {
            return; // 忽略空值
        }
        if (value instanceof Map<?, ?> map) {
            for (Map.Entry<?, ?> entry : map.entrySet()) {
                String key = String.valueOf(entry.getKey());
                String newPrefix = buildNestedKey(prefix, key);
                addParams(newPrefix, entry.getValue(), params, urlEncoded);
            }
        } else if (value instanceof List<?> list) {
            for (int i = 0, n = list.size(); i < n; i++) {
                Object object = list.get(i);
                String newPrefix = buildArrayKey(prefix, i);
                addParams(newPrefix, object, params, urlEncoded);
            }
        } else {
            String encodedKey, encodedValue;
            if (urlEncoded) {
                encodedKey = URLEncoder.encode(prefix, StandardCharsets.UTF_8);
                encodedValue = URLEncoder.encode(String.valueOf(value), StandardCharsets.UTF_8);
            } else {
                encodedKey = prefix;
                encodedValue = String.valueOf(value);
            }
            params.add(new BasicNameValuePair(encodedKey, encodedValue));
        }
    }

    private static String buildNestedKey(String prefix, String key) {
        return prefix.isEmpty() ? key : prefix + "[" + key + "]";
    }

    private static String buildArrayKey(String prefix, int index) {
        return prefix + "[" + index + "]"; // PHP兼容的数组表示方式
    }

    private String extractArrayIndex(String key) {
        // 正则匹配方括号内的数字，如：idArr[10]
        Pattern pattern = Pattern.compile("\\[(\\d+)]");
        Matcher matcher = pattern.matcher(key);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return key;
    }

}
